Flutter PlatformViewsController

PlatformViewsController 是 Flutter 内嵌原生视图能力在 Android 的管理类。

PlatformViewsChannel 只负责接收和解析消息,但不包含处理逻辑。处理逻辑都转发到 PlatformViewsController 来进行实际处理。另外一点,不论是 Virtual displays 模式还是 Hybrid composition 模式,底层都由 PlatformViewsController 统一处理。

除了嵌原生视图之外,该类还负责外接纹理的纹理管理。


核心成员

PlatformViewsController 类成员都是重量级选手:

成员 类型 说明 备注
registry PlatformViewRegistryImpl 所有平台视图的注册表
androidTouchProcessor AndroidTouchProcessor Android 手势处理器
context Context Android Context
flutterView FlutterView Android FlutterView,用于展示 Flutter UI 的视图
textureRegistry TextureRegistry 纹理注册表
textInputPlugin TextInputPlugin Flutter 在 Android 侧的输入插件
platformViewsChannel PlatformViewsChannel 与 Flutter 通信的 Channel 参见笔记《Flutter PlatformViewsChannel
accessibilityEventsDelegate AccessibilityEventsDelegate Semantic 辅助功能相关
vdControllers HashMap<Integer, VirtualDisplayController> VirtualDisplay 的注册表 VirtualDisplayController:是用于管理虚拟显示的控制器
contextToPlatformView HashMap<Context, View> 虚拟显示中的实际视图 键是Context对象,值是View对象。每个虚拟显示都有一个唯一的ContextView是Android中的视图,这里特指平台视图。这个映射用于根据Context查找在同一个虚拟显示中的平台视图。
platformViews SparseArray<PlatformView> Hybrid composition 模式下的平台视图
platformViewParent SparseArray<FlutterMutatorView> HC 平台视图的父视图 这是一个SparseArray,它存储了FlutterMutatorView对象。FlutterMutatorView是一个特殊的视图,它可以对其子视图(即平台视图)应用一些操作,如变换矩阵或设置透明度。
overlayLayerViews SparseArray<FlutterImageView> HC 平台视图的 Overlay UI 这也是一个SparseArray,它存储了FlutterImageView对象。FlutterImageView 是一个视图,它可以显示一个 Flutter 渲染的图像。
nextOverlayLayerId int 用于生成下一个图层的唯一ID 默认值为 0
flutterViewConvertedToImageView boolean 跟踪 flutterView 是否已经被转换为 FlutterImageView 默认值为 false
synchronizeToNativeViewHierarchy boolean 设置是否在添加平台视图时,将 flutterView的渲染表面转换为FlutterImageView 默认值 true
currentFrameUsedOverlayLayerIds HashSet<Integer> 储了在当前帧中显示的图层的ID
currentFrameUsedPlatformViewIds HashSet<Integer> 储了在当前帧中显示的平台视图的ID
motionEventTracker MotionEventTracker 获取原始的触摸事件

PlatformViewsHandler

除了上述成员外,还有一个 PlatformViewsHandler,它实现了 PlatformViewsChannel 的 PlatformViewsHandler 接口,参见《Flutter PlatformViewsChannel#PlatformViewsHandler 接口》。

其功能是,PlatformViewsChannel 收到 Flutter 侧操作请求后,通过该类转到 PlatformViewsController 中处理。

channelHandler 属性是你个匿名内部类:

private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
    new PlatformViewsChannel.PlatformViewsHandler() {
      @Override
      public void createAndroidViewForPlatformView(
          @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
        //...
      }

      @Override
      public void disposeAndroidViewForPlatformView(int viewId) {
        //..
      }

      //...
}

上面代码仅用于释义,channelHandler 内部类实现了 PlatformViewsHandler 接口。这些接口的实现逻辑非常关键,将在后面小节中介绍。


Virtual displays 模式

createVirtualDisplayForPlatformView 创建

首先看 PlatformViewsHandler 的 Virtual displays 模式下创建原生视图的过程:

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public long createVirtualDisplayForPlatformView(
    @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
  // 省略一些校验逻辑...

  // 解码创建参数
  Object createParams = null;
  if (request.params != null) {
    createParams = viewFactory.getCreateArgsCodec().decodeMessage(request.params);
  }

  // 屏幕尺寸
  int physicalWidth = toPhysicalPixels(request.logicalWidth);
  int physicalHeight = toPhysicalPixels(request.logicalHeight);
  validateVirtualDisplayDimensions(physicalWidth, physicalHeight);

  // 创建 SurfaceTexture
  TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
  // 创建 Flutter 控制 VirtualDisplay 的控制器
  VirtualDisplayController vdController =
      VirtualDisplayController.create(
          context,
          accessibilityEventsDelegate,
          viewFactory,
          textureEntry,
          physicalWidth,
          physicalHeight,
          request.viewId,
          createParams,
          (view, hasFocus) -> {
            if (hasFocus) {
              platformViewsChannel.invokeViewFocused(request.viewId);
            }
          });

  // ...

  // If our FlutterEngine is already attached to a Flutter UI, provide that Android
  // View to this new platform view.
  if (flutterView != null) {
    vdController.onFlutterViewAttached(flutterView);
  }

  vdControllers.put(request.viewId, vdController);
  View platformView = vdController.getView();
  platformView.setLayoutDirection(request.direction);
  // 这里还对 Context 有所采集,需要注意
  contextToPlatformView.put(platformView.getContext(), platformView);

  // 返回纹理 id
  return textureEntry.id();
}

其中,textureRegistry.createSurfaceTexture 实现类位于 FlutterRenderer,创建了一个 SurfaceTexture 实例,并将其注册进 FlutterEngine 中:

/**
 * Creates and returns a new {@link SurfaceTexture} managed by the Flutter engine that is also
 * made available to Flutter code.
 */
@Override
public SurfaceTextureEntry createSurfaceTexture() {
  Log.v(TAG, "Creating a SurfaceTexture.");
  final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
  return registerSurfaceTexture(surfaceTexture);
}

/**
 * Registers and returns a {@link SurfaceTexture} managed by the Flutter engine that is also made
 * available to Flutter code.
 */
@Override
public SurfaceTextureEntry registerSurfaceTexture(@NonNull SurfaceTexture surfaceTexture) {
  surfaceTexture.detachFromGLContext();
  final SurfaceTextureRegistryEntry entry =
      new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(), surfaceTexture);
  Log.v(TAG, "New SurfaceTexture ID: " + entry.id());
  registerTexture(entry.id(), entry.textureWrapper());
  return entry;
}

其中,SurfaceTexture 是 Android 系统提供的底层图形渲染组件,其功能为:

Android 的 SurfaceTexture 提供了一种高效的方法,通过 OpenGL ES 将图像流中的帧捕获并作为纹理渲染。这意味着,您可以将来自摄像头、视频文件或其他图像流的帧直接渲染到OpenGL环境中,而不需要进行复杂的数据转换或处理。这样做的好处是能够实现高性能和低延迟的图像处理和显示,非常适合需要实时视频处理的应用,比如视频聊天、增强现实(AR)应用等。

Flutter VirtualDisplayController 是专门负责 Android VirtualDisplay 逻辑的控制器(详情可点击阅读 Flutter VirtualDisplayController ),在 Flutter VirtualDisplayController 的构造函数中会创建 Flutter SingleViewPresentation,在 Presentation 内部会真正创建原生视图。

vdController.onFlutterViewAttached(flutterView); 这步,Flutter VirtualDisplayController 实现逻辑为:

/** See {@link PlatformView#onFlutterViewAttached(View)} */
/*package*/ void onFlutterViewAttached(@NonNull View flutterView) {
  if (presentation == null || presentation.getView() == null) {
    return;
  }
  presentation.getView().onFlutterViewAttached(flutterView);
}

Flutter SingleViewPresentationgetView() 将返回 PlatformView,PlatformView 是供开发者在 Native 侧创建的原生视图类。给原生视图一个时机,获取到当前容器的 FlutterView。代码中有一个判断分支,引擎与 FlutterView 不总是绑定状态,当 App 切后台后,两者将会解绑。如果是后台状态下创建的平台视图,这个回调将会在未来返回前台后调用。


detach

这个方法的主要作用是断开PlatformViewsController的连接,通常在Flutter应用程序切换到后台运行或被销毁时调用。

断开后,将停止处理平台视图消息,销毁所有的覆盖层表面,以及释放对Android上下文对象和纹理注册表的引用。

@UiThread
public void detach() {
  if (platformViewsChannel != null) {
    platformViewsChannel.setPlatformViewsHandler(null);
  }
  destroyOverlaySurfaces();
  platformViewsChannel = null;
  context = null;
  textureRegistry = null;
}

Usage:


detachFromView

detachFromView方法的作用是将PlatformViewsController和其FlutterEngine从渲染Flutter UI的Android View中分离,包括销毁所有的覆盖层表面,从Flutter视图中移除所有的覆盖层视图,以及通知所有的VirtualDisplayController对象Flutter视图已经被分离。

这个方法的主要作用是将PlatformViewsController和其FlutterEngine从渲染Flutter UI的Android View中分离。

public void detachFromView() {
  destroyOverlaySurfaces();
  removeOverlaySurfaces();
  this.flutterView = null;
  flutterViewConvertedToImageView = false;

  // Inform all existing platform views that they are no longer associated with
  // a Flutter View.
  for (VirtualDisplayController controller : vdControllers.values()) {
    controller.onFlutterViewDetached();
  }
}

其中:


FlutterMutatorView 声明周期管理

FlutterMutatorView 是 Hybrid composition 模式下,用于封装 PlatformView 的布局。

在 PlatformViewsController 中,有一个 SparseArray 列表进行管理:

// The platform view parents that are appended to `FlutterView`.
// If an entry in `platformViews` doesn't have an entry in this array, the platform view isn't
// in the view hierarchy.
//
// This view provides a wrapper that applies scene builder operations to the platform view.
// For example, a transform matrix, or setting opacity on the platform view layer.
//
// This is only applies to hybrid composition.
private final SparseArray<FlutterMutatorView> platformViewParent;

创建时机 initializePlatformViewIfNeeded:

/**
 * Initializes a platform view and adds it to the view hierarchy.
 *
 * @param viewId The view ID. This member is not intended for public use, and is only visible for
 *     testing.
 */
@VisibleForTesting
void initializePlatformViewIfNeeded(int viewId) {
  final PlatformView platformView = platformViews.get(viewId);
  // ...
  // 创建 FlutterMutatorView 实例
  final FlutterMutatorView parentView =
      new FlutterMutatorView(
          context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);

  parentView.setOnDescendantFocusChangeListener(
      (view, hasFocus) -> {
        if (hasFocus) {
          platformViewsChannel.invokeViewFocused(viewId);
        } else if (textInputPlugin != null) {
          textInputPlugin.clearPlatformViewClient(viewId);
        }
      });
  // 添加到 platformViewParent
  platformViewParent.put(viewId, parentView);
  // 将 FlutterMutatorView 添加到它的父布局中
  parentView.addView(platformView.getView());
  flutterView.addView(parentView);
}

FlutterMutatorView 什么时候从父布局中删除的?


本文作者:Maeiee

本文链接:Flutter PlatformViewsController

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!